package com.fishbone.secure.config;

import com.fishbone.secure.dynamic.DynamicFilterInvocationSecurityMetadataSource;
import com.fishbone.secure.dynamic.RequestMatcherCreator;
import com.fishbone.secure.service.MetaResourceService;
import com.fishbone.secure.service.RoleService;
import com.fishbone.secure.service.impl.DefaultMetaResourceService;
import com.fishbone.secure.service.impl.DefaultRoleService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author huyaxi
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({SecurityProperties.class, FishBoneSecureProperties.class})
@Import({ FishBoneWebSecurityConfiguration.class, FishBoneSecurityEnablerConfiguration.class})
public class FishBoneSecurityAutoConfiguration {

    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    String jwkSetUri;

    @Bean
    JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
                .build();
    }


    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


    /**
     * RequestMatcher 生成器
     *
     * @return RequestMatcher
     */
    @Bean
    public RequestMatcherCreator requestMatcherCreator() {
        return metaResources -> metaResources.stream()
                .map(metaResource -> new AntPathRequestMatcher(metaResource.getPattern(), metaResource.getMethod()))
                .collect(Collectors.toSet());
    }


    /**
     * 元数据加载器
     *
     * @return dynamicFilterInvocationSecurityMetadataSource
     */
    @Bean
    public FilterInvocationSecurityMetadataSource dynamicFilterInvocationSecurityMetadataSource() {
        return new DynamicFilterInvocationSecurityMetadataSource();
    }

    /**
     *  角色投票器
     * @return roleVoter
     */
    @Bean
    public RoleVoter roleVoter() {
        return new RoleVoter();
    }

    /**
     *  基于肯定的访问决策器
     *
     * @param decisionVoters  AccessDecisionVoter类型的 Bean 会自动注入到 decisionVoters
     * @return affirmativeBased
     */
    @Bean
    public AccessDecisionManager affirmativeBased(List<AccessDecisionVoter<?>> decisionVoters) {
        return new AffirmativeBased(decisionVoters);
    }

    @Bean
    public MetaResourceService metaResourceService(RestTemplate restTemplate){
        return new DefaultMetaResourceService(restTemplate);
    }


    @Bean
    public RoleService roleService(RestTemplate restTemplate){
        return new DefaultRoleService(restTemplate);
    }

}
